/*
 * Copyright © 2024-2025 Wenze Wei
 *
 * This file is part of StadionOS.
 *
 * This Source Code Form is subject to the terms of the GNU General Public License, v. 2.0.
 * You can obtain a copy of the GPL at
 * https://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 */

#include "output.h"
#include "compositor.h"

static void output_frame_notify(struct wl_listener *listener, void *data);

void output_init(struct onatu_output *output, struct wlr_output *wlr_output,
                 struct wlr_allocator *allocator, struct wlr_renderer *renderer,
                 struct onatu_compositor *compositor) {
    output->wlr_output = wlr_output;
    output->compositor = compositor;

    if (!wlr_output_init_render(wlr_output, allocator, renderer)) {
        wlr_log(WLR_ERROR, "Failed to initialize output renderer");
        return;
    }

    struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
    if (mode) {
        wlr_output_set_mode(wlr_output, mode);
        wlr_output_enable(wlr_output, true);

        float max_density = 1.0f;
        int total_effective_width = 0;
        struct onatu_output *iter;
        wl_list_for_each(iter, &compositor->outputs, link) {
            float density = iter->wlr_output->scale;
            if (density > max_density) {
                max_density = density;
            }
        }

        wl_list_for_each(iter, &compositor->outputs, link) {
            total_effective_width += iter->wlr_output->width * (iter->wlr_output->scale / max_density);
        }

        compositor->max_height = 0;
        compositor->total_width = 0;

        wl_list_for_each(iter, &compositor->outputs, link) {
            compositor->max_height = fmaxf(compositor->max_height, iter->wlr_output->height);
            compositor->total_width += iter->wlr_output->width * (iter->wlr_output->scale / max_density);
        }

        if (wlr_output->height > compositor->max_height) {
            output->y = compositor->max_height;
            output->x = 0;
            compositor->max_height = wlr_output->height;
        } else {
            output->x = compositor->total_width;
            output->y = 0;
            compositor->total_width += wlr_output->width * (wlr_output->scale / max_density);
        }
 
        wlr_output_layout_add(compositor->output_layout, wlr_output, output->x, 0);
        
        wlr_output_set_scale(wlr_output, max_density);
        wlr_output_enable_adaptive_sync(wlr_output, true);
    }

    output->frame.notify = output_frame_notify;
    wl_signal_add(&wlr_output->events.frame, &output->frame);
}

static void output_frame_notify(struct wl_listener *listener, void *data) {
    struct onatu_output *output = wl_container_of(listener, output, frame);
    
    struct wlr_scene_output *scene_output = wlr_scene_get_scene_output(output->compositor->scene, output->wlr_output);
    wlr_scene_output_commit(scene_output, NULL);

    struct wlr_scene_blur *blur = wlr_scene_blur_create(
        output->compositor->scene,
        10,
        0.7
    );
    wlr_scene_node_lower_to_bottom(&blur->node);
    
    wlr_renderer_begin(output->compositor->renderer, output->wlr_output->width, output->wlr_output->height);
    wlr_scene_output_render(scene_output);
    
    struct wlr_output_state state;
    wlr_output_state_init(&state);
    wlr_output_state_set_gamma_lut(&state, 256, output->compositor->color_correction_lut, output->compositor->color_correction_lut, output->compositor->color_correction_lut);
    wlr_output_commit_state(output->wlr_output, &state);
    
    wlr_renderer_end(output->compositor->renderer);
    wlr_output_commit(output->wlr_output);
    wlr_scene_blur_destroy(blur);
}
